﻿#define _CRT_SECURE_NO_WARNINGS 1

//一、Linux编译器gcc/g++


//1.1背景知识

//1.1.1程序执行的四个阶段

//1.预处理（进行宏替换 / 去注释 / 条件编译 / 头文件展开等)
//2.编译（生成汇编)
//3.汇编（生成机器可识别代码）
//4.链接（生成可执行文件或库文件)

//1.1.2四个阶段的详细工作

//（1）预处理(进行宏替换)
//• 预处理功能主要包括宏替换,文件展开,条件编译,去注释等
//• 预处理指令是以#号开头的代码行
//• 实例 : gcc –E test.cpp –o test.i 
//• 选项“ -E”, 该选项的作用是让gcc在预处理结束后停止编译过程
//• 选项“ -o”是指目标文件,“.i”文件为已经过预处理的C原始程序
//• 选项“ -Dxxx”是指定义一个xxx的宏

//注意：(1)c/c++不仅仅是指vs、gcc、g++，更重要的是语言本身的头文件和库文件,
//在Linux下，查看头文件所在地方：ls /usr/include
//(2)定义宏不止可以在文件中，在gcc/g++命令行中也可以定义
//(3)预处理后，代码还是c语言

//（2）编译（生成汇编）
//• 在这个阶段中, gcc首先要检查代码的规范性、是否有语法错误等, 以确定代码的实际要做的工作,
//在检查无误后, gcc把代码翻译成汇编语言
//• 用户可以使用“-S”选项来进行查看, 该选项只进行编译而不进行汇编, 生成汇编代码
//• 实例 : gcc –S test.i –o test.s

//(3)汇编（生成机器可识别代码）
//• 汇编阶段是把编译阶段生成的“.s”文件转成目标文件
//• 读者在此可使用选项“ -c”就可看到汇编代码已转化为“.o”的二进制目标代码了
//• 实例 : gcc –c hello.s –o hello.o 

//（4）连接（生成可执行文件或库文件）
//• 在成功编译之后, 就进入了链接阶段，将可重定位目标二进制文件和库进行链接，形成可执行程序
//• 实例 : gcc test.o –o test.out 


//1.2gcc编译选项

//格式gcc[选项] 要编译的文件[选项][目标文件]

//选项
//-E：该选项的作用是让gcc在预处理结束后停止编译过程
//-o：是指形成指定目标文件,比如编译test.c形成test.out可执行文件:gcc test.c -o test.out
//-S:该选项只进行编译(程序的编译）但不进行汇编, 生成汇编代码，文件最后形成的“.o”文件叫做可重定位目标二进制文件，简称目标文件
//-c：将汇编代码转化为机器可以识别的二进制代码

//注意：
//汇编操作后形成的可重定位目标二进制文件是不可以独立执行的，虽然已经是二进制文件，但是必须要链接才能只能怪


//二、库

//2.1库的概念
//• 我们的C程序中，并没有定义“printf”的函数实现, 且在预编译中包含的“stdio.h”中也只有该
//函数的声明, 而没有定义函数的实现, 那么, 是在哪里实“printf”函数的呢 ? 
//• 答案是 : 系统把这些函数实现都被做到名为libc.so.6的库文件中去了, 在没有特别指定
//时, gcc会到系统默认的搜索路径“ /usr/lib”下进行查找, 也就是链接到libc.so.6库函数中去, 这样
//就能实现函数“printf”了, 而这也就是链接的作用

//注意：
//(1)库有的命名规则：lib（文件名字）.so.XXX
//(2)对于编译型语言，安装开发包，必定是下载安装对应的头文件和库文件
//(3)库起始就是把源文件（.c文件）经过一定的编译，然后打包，只给你提供一个文件即可，不用给你提供太多的源文件，也可以达到隐藏源文件的目的
//(4)也就是说：头文件提供发方法的声明，而库文件则是提供方法的实现=你的代码=软件
//(5)库文件也就是不让我们做重复的工作

//2.2静态库和动态库

//（1）静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运
//行时也就不再需要库文件了。其后缀名一般为“.a”
//（2）动态库与之相反, 在编译链接时并没有把库文件的代码加入到可执行文件中, 而是在程序执行时由
//运行时链接文件加载库, 这样可以节省系统的开销。动态库一般后缀名为“.so”, 如前面所述的
//libc.so.6就是动态库。gcc在编译时默认使⽤动态库。完成了链接之后, gcc就可以生成可执行文
//件, 如下所示。 gcc test.o –o test 
//• gcc默认生成的二进制程序，是动态链接的，这点可以通过 file/ldd 命令验证
//• 如果想让gcc生成静态的只需要在指令最后加上-static，例如：gcc test.c -o test_static -static

//注意：
//• Linux下，动态库XXX.so,静态库XXX.a
//• Windows下，动态库XXX.dll, 静态库XXX.lib
//• 动态库往往也被称为共享库

//总结：
//（1）动态库不能缺失，一旦对应的动态库缺失，影响的将不只是一个程序，可能导致很多个程序都无法正常的运行
//（2）在编译器使用静态库进行链接的时候，回将自己的方法拷贝到目标程序中，该程序以后便不再依赖静态库

//2.3动态链接和静态链接

//在我们的实际开发中，不可能将所有代码放在一个源文件中，所以会出现多个源文件，而且多个源文
//件之间不是独立的，而会存在多种依赖关系，如一个源文件可能要调用另一个源文件中定义的函数，
//但是每个源文件都是独立编译的，即每个* .c文件会形成一个* .o文件，为了满足前面说的依赖关系，则
//需要将这些源文件产生的目标文件进行链接，从而形成一个可以执行的程序。这个链接的过程就是静
//态链接。静态链接的缺点很明显:
//• 浪费空间：因为每个可执行程序中对所有需要的目标文件都要有一份副本，所以如果多个程序对
//同一个目标文件都有依赖，如多个程序中都调用了printf()函数，则这多个程序中都含有
//printf.o，所以同一个目标文件都在内存存在多个副本
//• 更新比较困难：因为每当库函数的代码修改了，这个时候就需要重新进行编译链接形成可执行程
//序。但是静态链接的优点就是，在可执行程序中已经具备了所有执行程序所需要的任何东西，在
//执行的时候运行速度快。

//动态链接的出现解决了静态链接中提到问题。动态链接的基本思想是把程序按照模块拆分成各个相对
//独立部分，在程序运行时才将它们链接在一起形成一个完整的程序，而不是像静态链接一样把所有程
//序模块都链接成一个单独的可执行文件，动态链接其实远比静态链接要常用得多，比如我们可以用ldd指令查看我们调用的库

//注意：
//动态链接只能使用动态库，静态链接只能使用静态库


//2.4总结：
//1.如果我们没有静态库，但是我们就要使用-static进行强行使用，这样是不可以的
//2.如果我们没有动态库，只有静态库，而且gcc可以找到，这样是可以使用静态库的，因为gcc知识优先默认找动态链接，而-static的本质就是改变优先级
//3.我们形成的不一定是纯的全部动态链接或静态链接，有可能是混合的
//4.我们一旦加了-static，所有链接要求全部变成静态链接
//5.可以使用file进行查看动静态链接的方式
//6.动态库对比静态库：
//动态库优点：因为是共享库，能有效的节省资源（磁盘空间、内存空间、网络空间等）
//动态库缺点：一旦确实，会导致各个程序都无法运行
//静态库优点：不依赖库，一旦形成可执行程序，程序可以独立运行
//静态库缺点：体积大、比较消耗资源


//三、debug和release


//debug在形成可执行程序的时候，添加了debug信息，所以debug下可以追踪和测试
//Linux下默认是release版本发布，但是如果想要debug版本发布，只需要加一个-g选项即可，
//在加了debug后，我们可以明显发先，debug版本下的文件大小更大了

